<?php

class CustomRepository implements IRepository
{

  /**
   *
   * @var DomObjModel
   */
  public $model;

  public function __construct($model)
  {
    $this->model = $model;
  }

  public function getModel()
  {
    return Domain::getObject($this->model);
  }

  /**
   *
   * @return Aggregate
   */
  public function find($id = null, $params = array())
  {
    $model = $this->getModel();

    $q = $this->getBasicQuery($params);

    $data = (array) sy_get_param((array) $params, 'data');

    if ($id) {
      $main = $model->getTable();

      $pk = $model->getField($model->getPk())->getName();

      $q->where("$main.$pk = :$pk");

      $data[$pk] = $id;
    }

    $q->limit(1);

    $row = $q->execute($data)->fetchRow();

    $obj = false;

    if (! empty($row)) {
      $obj = DomainMapper::inflate($this->model, $row);
    }

    return $obj;
  }

  public function findAll($params = array())
  {
    $q = $this->getBasicQuery($params);

    $data = (array) sy_get_param((array) $params, 'data');

    $data = $q->execute($data)->fetchAll();

    $objs = array();

    foreach ($data as $row) {
      $objs[] = DomainMapper::inflate($this->model, $row);
    }

    return new ArrayObject($objs);
  }

  public function findCount($params = array())
  {
    $model = $this->getModel();

    $main = $model->getTable();

    $pk = $model->getField($model->getPk())->getName();

    $data = (array) sy_get_param((array) $params, 'data');

    $q = DB::getInstance()->query()->setParams($params)->from($main)->select("COUNT($pk) AS count");

    $count = $q->execute($data)->fetchOne('count');

    return $count;
  }

  public function save(&$data)
  {
    $model = $this->getModel();

    $pk = $model->getPk();

    if (isset($data[$pk])) {
      $result = $this->update($data);
    }
    else {
      $result = $this->insert($data);
    }

    $data->commit();

    return $result;
  }

  protected function insert(&$data)
  {
    $model = $this->getModel();

    $_data = array();

    $pk = $model->getPkField()->getName();

    foreach ($model->getFields() as $field => $_model) {
      $_field = $model->getField($field);

      $name = $_field->getName();
      $table = $_field->getTable();

      if (empty($table)) {
        $table = $model->getTable();
      }

      if ($name && isset($data[$field])) {
        $_data[$table][$name] = $data[$field];
      }
    }

    $main = true;

    foreach ($_data as $table => $__data) {
      if ($main) {
        DB::getInstance()->insert($table, $__data)->execute($__data);

        $data[$model->getPk()] = $id = DB::getInstance()->lastInsertId();

        $main = false;
      }
      else {
        $__data[$pk] = $id;

        DB::getInstance()->insert($table, $__data)->execute($__data);
      }
    }
  }

  protected function update(&$data)
  {
    $model = $this->getModel();

    $_data = array();

    $pk = $model->getPkField()->getName();

    $id = $data[$model->getPk()];

    foreach ($model->getFields() as $field => $_model) {
      $_field = $model->getField($field);

      $name = $_field->getName();
      $table = $_field->getTable();

      if (empty($table)) {
        $table = $model->getTable();
      }

      if ($name && isset($data[$field])) {
        $_data[$table][$name] = $data[$field];
      }
    }

    $main = true;

    foreach ($_data as $table => $__data) {
      if ($main) {
        $main = false;
      }
      else {
        $__data[$pk] = $id;
      }

      DB::getInstance()->update($table, $__data, "$pk = :$pk")->execute($__data);
    }
  }

  public function delete($id, $params = array())
  {
  }

  public function deleteAll($params)
  {
  }

  protected function getBasicQuery($params = null)
  {
    $model = $this->getModel();

    $q = DB::getInstance()->query()->setParams($params);

    $main = $model->getTable();

    $q->from($main);

    $tables = $model->getTables();

    if (count($tables) > 1) {
      $pk = $model->getField($model->getPk())->getName();

      for ($i = 1; $i < count($tables); $i++) {
        $table = $tables[$i];

        $q->leftJoin("$table ON ($table.$pk = users.$pk)");
      }
    }

    foreach ($model->getFields() as $name => $_model) {
      $field = $model->getField($name);

      $q->select($field->getSql($main));
    }

    return $q;
  }

}
